#include <iostream>
#include <windows.h>

#include <thread> // 添加线程头文件
using namespace std;

#if 0
// 1. 并发,进程,线程,概念,实现
// 1.1 并发,多个任务(独立的活动),同时发生.一个程序同时执行多个独立的任务.
// 以往只有单核cpu,同一时刻只能执行一个任务,由操作系统调度,每秒钟进行多次所谓的任务切换.
// 这种是并行,是并发的假象,这种切换是上下文切换,切换的时候,是有时间开销,恢复一些变量值.各种状态,各种执行进度,执行的时候,要复原这些信息.

// 多cpu,用于服务器和高性能计算机领域.在一块芯片上,有多核,4核.
// 能够给实现真正的并行执行多个任务(硬件并发)
// 使用并发的原因,主要是同时干多个事情,提高性能.

// 1.2 可执行程序
// 硬盘上的一个文件,exe, x执行权限.
// 1.3 进程: 就是一个可执行程序运行起来了,就叫创建了一个进程.
// 1.4 线程
// 每个进程(执行起来的可执行程序),都有一个主线程,这个主线程是唯一的,也就是一个进程中只有一个主线程.
// 当你执行要给可执行程序,产生了一个进程后,这个主线程就随着这个进程默默的启动起来了.
// ctrl+f5运行这个程序的时候,实际上是进程的主线程来执行(调用)这个main函数的代码.
// 线程是用来执行代码的.线程会走一条代码的执行道路.可以创建多个线程.
// 每创建一个新线程,就可以在同一时刻,多干一个不同的事.
// 多线程(并发),并不是越多越好,都需要一个独立的堆栈空间(1M),线程之间的切换要保存很多中间状态,
// 切换会耗费本该属于程序运行的时间.

// 总结线程:
// 1.线程是用来执行代码的
// 2.主线程随着进程的默默启动并运行,不建议超过200-300个
// 3.开发多线程程序,实力的体现,一个是商用的必须需求.线程开发有一定的难度,实现代码更复杂,理解起来更难一些.
// 对于道路上成长特别关键,不要急于求成.
// 高薪,网络通讯.

// 并发的实现方式
// 两个多个任务同时发生
// 多个进程实现并发
// 单独的进程中,创建多个线程实现并发.

// 多个进程并发:进程之间通讯(同一电脑上:管道,文件,消息队列,共享内存)
// 不同电脑上通信,socket通信技术.

// 多线程并发: 单个进程中,创建了多个线程
// 线程是轻量级的进程,每个线程都有自己id独立的运行路径,但是一个进程中,所有线程共享地址空间.
// 全局变量,指针,引用,都可以线程之间传递.开销小于多进程.
// 共享内存带来新问题,数据不一致问题:线程A,线程B

// 多进程并发和多线程并发,虽然可以混合使用,但建议优先使用多线程技术手段,而不是多进程.

// 总结: 线程优点
// 1.线程启动速度更快,更轻量级
// 2.系统资源开销更少,执行速度更快.共享内存更快
// 3. 缺点:使用有一定难度,要小心处理数据的一致性问题

// c++新标准线程库
// windiows: CreateThread(). _beginthred(),_beginthreadxe()
// linux : pthread_create().创建线程
// 临界区,互斥量
// 以往的多线程代码不能跨平台;
// POSIX thread(pthread),跨平台,做一番配置,用起来不是那么方便

// c++新标准,增加了多线程支持,意味着可移植性,这就大大减少开发人员的工作量了.



#endif

// 添加线程初始函数
void myprintf()
{
    cout << "我的线程myprintf开始执行了" << endl;
    // ......
    // ......
    cout << "我的线程myprintf执行完毕了" << endl;
}

void myprintf1()
{
    cout << "我的线程myprintf开始执行了" << endl;
    Sleep(2000);
    // ......
    // ......
    cout << "我的线程myprintf执行完毕了" << endl;
}
void myprintf2()
{
    cout << "我的线程myprintf开始执行了" << endl;
    // ......
    int i = 0;
    cout << "我的线程myprintf开始执行了 : "<< i++ << endl;
    cout << "我的线程myprintf开始执行了 : "<< i++ << endl;
    cout << "我的线程myprintf开始执行了 : "<< i++ << endl;
    cout << "我的线程myprintf开始执行了 : "<< i++ << endl;
    cout << "我的线程myprintf开始执行了 : "<< i++ << endl;
    cout << "我的线程myprintf开始执行了 : "<< i++ << endl;
    cout << "我的线程myprintf开始执行了 : "<< i++ << endl;
    cout << "我的线程myprintf开始执行了 : "<< i++ << endl;
    cout << "我的线程myprintf开始执行了 : "<< i++ << endl;
    cout << "我的线程myprintf开始执行了 : "<< i++ << endl;
    cout << "我的线程myprintf开始执行了 : "<< i++ << endl;
    cout << "我的线程myprintf开始执行了 : "<< i++ << endl;
    cout << "我的线程myprintf开始执行了 : "<< i++ << endl;
    cout << "我的线程myprintf开始执行了 : "<< i++ << endl;
    cout << "我的线程myprintf开始执行了 : "<< i++ << endl;
    cout << "我的线程myprintf开始执行了 : "<< i++ << endl;
    // ......
    cout << "我的线程myprintf执行完毕了" << endl;
}

class TA
{
public:
    // 重载(),不能带参数
    void operator()()
    {
        cout << "TA operator() Start" << endl;
        // ......
        cout << "TA operator() End" << endl;
    }
};

class TA1
{
public:
    int &m_i;
    TA1(int &i):m_i(i)
    {
    }// 构造

public:
    // 重载(),不能带参数
    void operator()()
    {
        cout << "TA operator() Start" << endl;
        // ......
        cout << "m_i : " << m_i << endl;
        cout << "m_i : " << m_i << endl;
        cout << "m_i : " << m_i << endl;
        cout << "m_i : " << m_i << endl;
        cout << "m_i : " << m_i << endl;
        cout << "m_i : " << m_i << endl;
        cout << "m_i : " << m_i << endl;
        cout << "TA operator() End" << endl;
    }
};

class TA2
{
public:
    int &m_i;
    TA2(int &i):m_i(i)
    {
        cout << "TA2() 构造" << endl;// 添加构造证明
    }// 构造

    TA2(const TA2 &ta):m_i(ta.m_i)
    {
        cout << "TA2() 拷贝构造" << endl;
    }// 构造
    ~TA2()
    {
        cout << "~TA2()" << endl;
    }
public:
    // 重载(),不能带参数
    void operator()()
    {
        cout << "TA operator() Start" << endl;
        // ......
        cout << "m_i : " << m_i << endl;
        cout << "m_i : " << m_i << endl;
        cout << "m_i : " << m_i << endl;
        cout << "m_i : " << m_i << endl;
        cout << "m_i : " << m_i << endl;
        cout << "m_i : " << m_i << endl;
        cout << "m_i : " << m_i << endl;
        cout << "TA operator() End" << endl;
    }
};

int main()
{
    system("chcp 65001");
#if 0
    // 1.程序运行起来,生成一个进程,该进程所属的主线程就开始自动运行
    cout << "main Start!" << endl; // 主线程在执行.main执行完,进程就执行完毕.

    // 主线程从main开始执行,自己创建的线程,也需要从一个函数(初始函数),一旦这个函数运行完毕,就线程执行完毕了.
    // 整个进程是否执行完毕的标志是主线程是否执行完,如果是主线程执行完毕了,就代表整个进程就执行完毕了
    // 一般情况下,main执行完毕了,如果其他子线程还没有执行完毕,那么线程就强制终止.
    // 保证主线程的运行.

    // 创建线程
    // 1.包含头文件<thread>
    // 2.初始函数
    // 3.main函数写函数 std::
    thread mytobj(myprintf);
    mytobj.join();// 若注释掉erminate called without an active exception
    cout << "main end" << endl;
    // 现象是执行myprintf ,再"main end"
    // 明确一点,整个程序是两条线路在走.同时在干两个事情.

    // thread mytobj(myprintf);// 创建了线程,执行起点入口(myprintf()),2.myprintf这个线程开始执行
    // thread 是标准库的类.
    // myprintf是可调用对象.

    // mytobj.join();
    // join;加入/汇合,说白了,就是阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程回合
    // 等待myprintf执行完了.

    // 主线程执行完毕了,子进程没有执行完毕了,这种程序员是不合格,写出来的程序也是不稳定的
    // 一个良好的程序,应该是主线程等待子线程执行完毕后,自己才能够最终退出.
#endif

#if 0
    cout << "mythread strat" << endl;
    thread mythread(myprintf1);
    Sleep(1000);
    //    mythread strat
    //    我的线程myprintf开始执行了
    //    mythrad join
    //    我的线程myprintf执行完毕了
    //    main end

    // 说明了一点,thread mythread(myprintf); 就会立马调用 myprintf 函数执行,然后就会跳到主线程,去执行Sleep(2000); 此时myprintf已经执行了,等待2秒,此时主进程已经执行到了join();,它就会阻塞主线程,把子线程执行完毕后,再返回到主线程中去,执行main end
    cout << "mythrad join" << endl;
    mythread.join();
    cout << "main end" << endl;
#endif
#if 0
    // detach(); 主线程可以先溜,凡事都有意外.传统多线程程序主线程要等待子线程执行完毕,然后自己再最后退出.
    // detach : 分离,也就是主线程不和子线程汇合了,你主线程执行你的,我子线程执行我的,你主线程不必等待我子线程执行完毕了.
    // 为什么引入detach(),我们创建很多子线程,让主线程逐个等待子线程结束.逐个方法不太好
    // 一旦detach()之后,与这个主线程关联的thread对象,就会失去与这个主线程的关联.
    // 子线程就会驻留后台运行了,这个子线程就相当于被c++运行时刻接管了,当这个子线程执行完毕后,由运行库,清理该线程相关的资源,(守护线程)
    int i = 0;
    thread mytobj2(myprintf2);
    mytobj2.detach();// 若注释掉erminate called without an active exception

    cout << "main end : " <<  i++ << endl;
    cout << "main end : " <<  i++ << endl;
    cout << "main end : " <<  i++ << endl;
    cout << "main end : " <<  i++ << endl;

    // 当main return 0 了整个程序就执行完毕了,从而终止了所有的子线程了.
    // detach 一旦调用detach了,就不能再用join,不然就有异常;
    // 我们要控制线程的生命周期
#endif
#if 0
    // joinable() 判断是否可以使用join()或者detach(),在没有使用join()或者detach()的返回值是true;调用后是false,返回true是可以join()的
    thread mytobj3(myprintf2);
    cout << "mytobj3 joinable : " << mytobj3.joinable() << endl;
    mytobj3.join();
    cout << "mytobj3 joinable : " << mytobj3.joinable() << endl;
    cout << endl;
    thread mytobj4(myprintf2);
    cout << "mytobj4 joinable : " << mytobj4.joinable() << endl;
    mytobj4.join();
    cout << "mytobj4 joinable : " << mytobj4.joinable() << endl;
#endif

#if 0
    // 其他可创建线程的手法
    // thread mytobj3(myprintf2); 线程创建一个对象,这个对象可以是函数,也可以是类,
    TA ta;// 生成对象
    thread mytobj(ta);// TA 重载函数
    mytobj.join();
    cout << "main end" << endl;
#endif
#if 0
    // 主线程执行完毕,myi 引用 这个临时变量消失了,造成了变量不可预料的结果.不能是引用.
    // TA1 一旦调用了detach,主线程执行结束了,TA1肯定是不在了,这个对象不在了
    // 那么ta 是复制到线程中去,但复制的TA1对象依旧存在.
    int myi = 6;
    TA1 ta(myi);
    thread mytobj(ta);
    mytobj.detach();
    cout << "main end" << endl;
#endif
#if 0
    // 主线程执行完毕,myi 引用 这个临时变量消失了,造成了变量不可预料的结果.不能是引用.
    // TA2 一旦调用了detach,主线程执行结束了,TA2肯定是不在了,这个对象不在了
    // 那么ta 是复制到线程中去,但复制的TA2对象依旧存在.
    // 证明存在,
    int myi = 6;
    TA2 ta(myi);
    thread mytobj(ta);// 这里是拷贝构造函数
    mytobj.detach();
    cout << "main end" << endl;
#endif
#if 0
    // 用lambda 表达式
    auto mylamthread = []
    {
        cout << "我的线程mylamthread开始执行了" << endl;
        // ......
        // ......
        cout << "我的线程mylamthread执行完毕了" << endl;
    };// 有分号

    thread myjob(mylamthread);
    myjob.join();
     cout << "main end" << endl;
#endif


    return 0;
}
